/**
 * 场景协调器 - 连接 MVVM 和 ECS 的桥梁
 * 
 * 职责：
 * 1. 管理场景根节点和层级结构
 * 2. 为 ECS 提供场景节点访问接口
 * 3. 为 MVVM 提供游戏状态接口
 * 4. 协调两个架构的生命周期
 * 5. 管理预制体的加载和实例化
 * 
 * @author AI Assistant
 * @date 2025-11-26
 */

import { Node, Prefab, instantiate, Vec3, find } from "cc";
import { resLoader } from "../../core/resload";
import { Log } from "../../core/logger/LoggerGlobal";

/**
 * 场景层级配置
 */
export interface LayerConfig {
    name: string;
    zIndex: number;
    description?: string;
}

/**
 * 预制体实例化选项
 */
export interface InstantiateOptions {
    position?: Vec3;
    parent?: Node;
    layerName?: string;
    name?: string;
}

/**
 * 场景协调器统计信息
 */
export interface SceneStatistics {
    totalNodes: number;
    layerCount: number;
    prefabCacheCount: number;
    layers: Map<string, number>; // 每层节点数量
}

/**
 * 场景协调器类（使用依赖注入）
 */
export class SceneCoordinator {
    // 场景根节点
    private sceneRoot: Node | null = null;
    
    // 场景层级映射
    private layers: Map<string, Node> = new Map();
    
    // 预制体缓存（避免重复加载）
    private prefabCache: Map<string, Prefab> = new Map();
    
    // 节点引用池（便于查找和管理）
    private nodePool: Map<string, Node> = new Map();
    
    // 初始化状态
    private _initialized: boolean = false;
    
    // 默认层级配置
    private readonly DEFAULT_LAYERS: LayerConfig[] = [
        { name: 'background', zIndex: -100, description: '背景层' },
        { name: 'game', zIndex: 0, description: '游戏对象层' },
        { name: 'effect', zIndex: 100, description: '特效层' },
        { name: 'ui', zIndex: 200, description: 'UI层' },
        { name: 'top', zIndex: 300, description: '顶层（调试等）' }
    ];
    
    /**
     * 构造函数（公开，用于 DI）
     */
    constructor() {
        Log.scene.debug('SceneCoordinator 已创建（DI）');
    }
    
    /**
     * 初始化场景协调器
     * @param sceneRoot 场景根节点（从 game.ts 注入）
     * @param customLayers 自定义层级配置（可选）
     */
    init(sceneRoot: Node, customLayers?: LayerConfig[]): void {
        if (this._initialized) {
            Log.scene.warn('已经初始化，跳过重复初始化');
            return;
        }
        
        if (!sceneRoot || !sceneRoot.isValid) {
            Log.scene.error('无效的场景根节点');
            return;
        }
        
        this.sceneRoot = sceneRoot;
        
        // 创建层级
        const layerConfig = customLayers || this.DEFAULT_LAYERS;
        this.createLayers(layerConfig);
        
        this._initialized = true;
        
        Log.scene.info('✅ 初始化完成', {
            sceneRoot: sceneRoot.name,
            layerCount: this.layers.size
        });
    }
    
    /**
     * 创建场景层级
     */
    private createLayers(layerConfigs: LayerConfig[]): void {
        if (!this.sceneRoot) return;
        
        Log.scene.info('创建场景层级...');
        
        for (const config of layerConfigs) {
            // 检查是否已存在该层级
            let layer = this.sceneRoot.getChildByName(config.name);
            
            if (!layer) {
                // 创建新层级
                layer = new Node(config.name);
                layer.setPosition(0, 0, config.zIndex);
                this.sceneRoot.addChild(layer);
                
                Log.scene.debug('创建层级', {
                    name: config.name,
                    zIndex: config.zIndex
                });
            } else {
                Log.scene.debug('复用已有层级', { name: config.name });
            }
            
            // 存储层级引用
            this.layers.set(config.name, layer);
        }
    }
    
    /**
     * 获取指定层级节点
     * @param layerName 层级名称
     * @returns 层级节点，如果不存在则返回场景根节点
     */
    getLayer(layerName: string): Node | null {
        const layer = this.layers.get(layerName);
        if (!layer) {
            Log.scene.warn('层级不存在，返回场景根节点', { layerName });
            return this.sceneRoot;
        }
        return layer;
    }
    
    /**
     * 获取场景根节点
     */
    getSceneRoot(): Node | null {
        return this.sceneRoot;
    }
    
    /**
     * 获取所有层级名称
     */
    getLayerNames(): string[] {
        return Array.from(this.layers.keys());
    }
    
    /**
     * 实例化预制体到指定层级
     * @param bundleName bundle 名称
     * @param prefabPath 预制体路径
     * @param options 实例化选项
     * @returns 实例化的节点，失败返回 null
     */
    async instantiatePrefab(
        bundleName: string,
        prefabPath: string,
        options?: InstantiateOptions
    ): Promise<Node | null> {
        try {
            // 加载预制体
            const prefab = await this.loadPrefab(bundleName, prefabPath);
            if (!prefab) {
                Log.resource.error('预制体加载失败', {
                    bundle: bundleName,
                    path: prefabPath
                });
                return null;
            }
            
            // 实例化节点
            const node = instantiate(prefab);
            
            // 设置节点名称
            if (options?.name) {
                node.name = options.name;
            }
            
            // 设置位置
            if (options?.position) {
                node.setPosition(options.position);
            }
            
            // 添加到场景
            if (options?.parent) {
                // 使用指定父节点
                options.parent.addChild(node);
            } else {
                // 添加到指定层级
                const layerName = options?.layerName || 'game';
                const layer = this.getLayer(layerName);
                if (layer) {
                    layer.addChild(node);
                } else {
                    Log.scene.warn('层级不存在，添加到场景根节点', { layerName });
                    this.sceneRoot?.addChild(node);
                }
            }
            
            Log.scene.info('✅ 实例化预制体成功', {
                nodeName: node.name,
                bundle: bundleName,
                path: prefabPath
            });
            
            return node;
        } catch (error) {
            Log.scene.error('实例化预制体失败', {
                bundle: bundleName,
                path: prefabPath,
                error
            });
            return null;
        }
    }
    
    /**
     * 批量实例化预制体
     * @param bundleName bundle 名称
     * @param prefabPath 预制体路径
     * @param count 数量
     * @param options 实例化选项
     * @returns 实例化的节点数组
     */
    async instantiatePrefabBatch(
        bundleName: string,
        prefabPath: string,
        count: number,
        options?: InstantiateOptions
    ): Promise<Node[]> {
        const nodes: Node[] = [];
        
        // 先加载预制体（只加载一次）
        const prefab = await this.loadPrefab(bundleName, prefabPath);
        if (!prefab) {
            Log.resource.error('预制体加载失败', {
                bundle: bundleName,
                path: prefabPath
            });
            return nodes;
        }
        
        Log.scene.info('批量实例化预制体', {
            count,
            path: prefabPath
        });
        
        // 批量实例化
        for (let i = 0; i < count; i++) {
            const node = instantiate(prefab);
            
            if (options?.position) {
                node.setPosition(options.position);
            }
            
            const layerName = options?.layerName || 'game';
            const layer = this.getLayer(layerName);
            if (layer) {
                layer.addChild(node);
            }
            
            nodes.push(node);
        }
        
        Log.scene.info('✅ 批量实例化完成', {
            nodeCount: nodes.length
        });
        
        return nodes;
    }
    
    /**
     * 加载预制体（带缓存）
     * @param bundleName bundle 名称
     * @param prefabPath 预制体路径
     * @returns 预制体资源
     */
    async loadPrefab(bundleName: string, prefabPath: string): Promise<Prefab | null> {
        const cacheKey = `${bundleName}:${prefabPath}`;
        
        // 检查缓存
        if (this.prefabCache.has(cacheKey)) {
            return this.prefabCache.get(cacheKey)!;
        }
        
        try {
            // 加载预制体
            const prefab = await resLoader.loadAsync(bundleName, prefabPath, Prefab);
            
            if (prefab) {
                // 缓存预制体
                this.prefabCache.set(cacheKey, prefab);
                Log.resource.debug('预制体已缓存', { cacheKey });
            }
            
            return prefab;
        } catch (error) {
            Log.resource.error('加载预制体失败', {
                cacheKey,
                error
            });
            return null;
        }
    }
    
    /**
     * 创建空节点
     * @param name 节点名称
     * @param layerName 层级名称
     * @param position 位置（可选）
     * @returns 创建的节点
     */
    createNode(name: string, layerName: string = 'game', position?: Vec3): Node {
        const node = new Node(name);
        
        if (position) {
            node.setPosition(position);
        }
        
        const layer = this.getLayer(layerName);
        if (layer) {
            layer.addChild(node);
        }
        
        Log.scene.debug('创建空节点', {
            name,
            layer: layerName,
            position: position ? `(${position.x}, ${position.y}, ${position.z})` : 'default'
        });
        
        return node;
    }
    
    /**
     * 销毁节点
     * @param node 要销毁的节点
     * @param immediate 是否立即销毁（默认 false）
     */
    destroyNode(node: Node, immediate: boolean = false): void {
        if (!node || !node.isValid) {
            Log.scene.warn('尝试销毁无效节点');
            return;
        }
        
        const nodeName = node.name;
        
        if (immediate) {
            node.destroyAllChildren();
            node.destroy();
        } else {
            node.destroy();
        }
        
        Log.scene.debug('销毁节点', {
            nodeName,
            immediate
        });
    }
    
    /**
     * 查找节点
     * @param path 节点路径（相对于场景根节点）
     * @returns 找到的节点，不存在返回 null
     */
    findNode(path: string): Node | null {
        if (!this.sceneRoot) return null;
        
        const node = find(path, this.sceneRoot);
        if (!node) {
            Log.scene.warn('未找到节点', { path });
        }
        return node;
    }
    
    /**
     * 清理指定层级的所有节点
     * @param layerName 层级名称
     */
    clearLayer(layerName: string): void {
        const layer = this.layers.get(layerName);
        if (!layer) {
            Log.scene.warn('层级不存在', { layerName });
            return;
        }
        
        const childCount = layer.children.length;
        layer.destroyAllChildren();
        
        Log.scene.info('清理层级', {
            layerName,
            nodeCount: childCount
        });
    }
    
    /**
     * 清理所有层级（保留层级结构）
     */
    clearAllLayers(): void {
        Log.scene.info('清理所有层级...');
        
        for (const [layerName, layer] of this.layers) {
            const childCount = layer.children.length;
            if (childCount > 0) {
                layer.destroyAllChildren();
                Log.scene.debug('清理层级', {
                    layerName,
                    nodeCount: childCount
                });
            }
        }
    }
    
    /**
     * 获取统计信息
     */
    getStatistics(): SceneStatistics {
        const stats: SceneStatistics = {
            totalNodes: 0,
            layerCount: this.layers.size,
            prefabCacheCount: this.prefabCache.size,
            layers: new Map()
        };
        
        for (const [layerName, layer] of this.layers) {
            const nodeCount = layer.children.length;
            stats.layers.set(layerName, nodeCount);
            stats.totalNodes += nodeCount;
        }
        
        return stats;
    }
    
    /**
     * 打印统计信息
     */
    printStatistics(): void {
        const stats = this.getStatistics();
        
        Log.performance.info('\n=== 场景协调器统计信息 ===');
        Log.performance.info(`总节点数: ${stats.totalNodes}`);
        Log.performance.info(`层级数量: ${stats.layerCount}`);
        Log.performance.info(`预制体缓存: ${stats.prefabCacheCount}`);
        Log.performance.info('\n层级详情:');
        
        for (const [layerName, nodeCount] of stats.layers) {
            Log.performance.info(`  - ${layerName}: ${nodeCount} 个节点`);
        }
        
        Log.performance.info('========================\n');
    }
    
    /**
     * 清理预制体缓存
     */
    clearPrefabCache(): void {
        const cacheCount = this.prefabCache.size;
        this.prefabCache.clear();
        Log.resource.info('清理预制体缓存', { cacheCount });
    }
    
    /**
     * 重置场景协调器
     */
    reset(): void {
        Log.scene.info('重置场景协调器');
        
        // 清理所有层级
        this.clearAllLayers();
        
        // 清理预制体缓存
        this.clearPrefabCache();
        
        // 清理节点池
        this.nodePool.clear();
    }
    
    /**
     * 销毁场景协调器
     */
    destroy(): void {
        Log.scene.info('销毁场景协调器');
        
        // 清理所有资源
        this.reset();
        
        // 清理层级引用
        this.layers.clear();
        
        // 重置状态
        this.sceneRoot = null;
        this._initialized = false;
    }
    
    /**
     * 检查是否已初始化
     */
    isInitialized(): boolean {
        return this._initialized;
    }
}

/**
 * 使用说明：
 * 
 * SceneCoordinator 现在使用依赖注入，不再是单例。
 * 
 * 通过 DI 容器获取实例：
 * ```typescript
 * import { container, ServiceIdentifiers } from '../../core/di';
 * const sceneCoordinator = container.resolve<SceneCoordinator>(ServiceIdentifiers.SceneCoordinator);
 * ```
 */
